package com.xbongbong.paas.business.rule;

import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.enums.BusinessRuleExecuteEnum;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.RuleOperationEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.FilterConditionsPoJo;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.pojo.ActiveRulePoJo;
import com.xbongbong.paas.pojo.BusinessRulesPoJo;
import com.xbongbong.paas.pojo.OperationsPojo;
import com.xbongbong.paas.pojo.RulePoJo;
import com.xbongbong.paas.pojo.dto.ActiveRuleDTO;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataUpdateDTO;
import com.xbongbong.paas.pojo.dto.InactiveRuleDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.businessrule.pojo.BusinessRuleConditionPojo;
import com.xbongbong.pro.businessrule.pojo.BusinessRuleInfoPojo;
import com.xbongbong.pro.businessrule.pojo.dto.OperationDTO;
import com.xbongbong.pro.businessrule.pojo.dto.OperatorBatchDTO;
import com.xbongbong.pro.businessrulelog.pojo.BusinessRuleLogSaveDTO;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.form.pojo.RuleTargetPojo;
import com.xbongbong.pro.form.pojo.vo.FormBusinessRuleVO;
import com.xbongbong.pro.formdata.pojo.vo.BeforeSaveVO;
import com.xbongbong.pro.formdata.pojo.vo.BeforeUpdateVO;
import com.xbongbong.pro.formdata.pojo.vo.UpdateVO;
import com.xbongbong.pro.rabbitmq.producer.BusinessRuleProducer;
import com.xbongbong.saas.domain.entity.WorkOrderExplainEntity;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.model.PaasFormSubDataModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;



/**
 * @author: wufeng
 * @date: 2018/12/28 16:42
 * @desrcption: 表单数据生效规则
 */
@Component
public class FormDataActiveRuleHelp extends AbstractRuleHelp {

    private static final Logger LOG = LoggerFactory.getLogger(FormDataActiveRuleHelp.class);



    @Resource
    private BusinessRuleProducer businessRuleProducer;
    @Resource
    private FormDataInactiveRuleHelp formDataInactiveRuleHelp;
    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private BusinessRuleUserPermissionHelp businessRuleUserPermissionHelp;
    @Resource
    private BusinessRuleInfoService businessRuleInfoService;
    @Resource
    private BusinessRuleConditionHelp businessRuleConditionHelp;
    @Resource
    private PaasFormSubDataModel paasFormSubDataModel;
    @Resource
    private IndexTypeModel indexTypeModel;


    /**
     * 编辑执行业务规则
     * @param formDataUpdateDTO
     * @param beforeUpdateVO
     * @param updateVO
     * @throws XbbException
     */
    public void activeRule(FormDataUpdateDTO formDataUpdateDTO, BeforeUpdateVO beforeUpdateVO, UpdateVO updateVO) throws XbbException{
        PaasFormEntityExt paasFormEntityExt = beforeUpdateVO.getPaasFormEntityExt();
        String businessRules = paasFormEntityExt.getBusinessRules();
        if (Objects.equals("1", businessRules) && Objects.equals(1, updateVO.getUpdateLine())) {
            PaasFormDataEntity newFormData = beforeUpdateVO.getPaasFormDataEntity();
            PaasFormDataEntity oldPaasFormDataEntity = beforeUpdateVO.getOldPaasFormData();
            IndexTypeEnum indexTypeEnum = indexTypeModel.getSubIndexType(formDataUpdateDTO.getCorpid(), formDataUpdateDTO.getBusinessType(), formDataUpdateDTO.getSaasMark());
            paasFormSubDataModel.transferSubForm(oldPaasFormDataEntity, indexTypeEnum);
            ActiveRuleDTO activeRuleDTO = new ActiveRuleDTO(new ArrayList<>(), newFormData,  oldPaasFormDataEntity, beforeUpdateVO.getExplainList(), formDataUpdateDTO.getDataId(),
                    formDataUpdateDTO.getBusinessType(), formDataUpdateDTO.getSaasMark(), formDataUpdateDTO.getCorpid(),formDataUpdateDTO.getLoginUser(), 1, formDataUpdateDTO.getPlatform(),
                    formDataUpdateDTO.getHttpHeader(), formDataUpdateDTO.getBrowserInfo(), formDataUpdateDTO.getIp(), formDataUpdateDTO.getLocale(), formDataUpdateDTO.getIsImport());
            // 编辑触发业务规则
            activeRule(activeRuleDTO);
        }
    }

    /**
     * 新建-执行业务规则
     * @param formDataAddDTO
     * @param beforeSaveVO
     * @param newPaasFormDataEntity 数据实体
     * @param paasFormEntityExt 表单实体
     * @throws XbbException
     */
    public void activeRule(FormDataAddDTO formDataAddDTO, BeforeSaveVO beforeSaveVO, PaasFormDataEntity newPaasFormDataEntity, PaasFormEntityExt paasFormEntityExt) throws XbbException{
        String businessRules = paasFormEntityExt.getBusinessRules();
        if (!Objects.equals(1, formDataAddDTO.getIsBusinessRule()) && Objects.equals("1", businessRules)) {
            ActiveRuleDTO activeRuleDTO = new ActiveRuleDTO();
            BeanUtil.copyProperties(formDataAddDTO, activeRuleDTO);
            activeRuleDTO.setDataId(newPaasFormDataEntity.getId());
            activeRuleDTO.setPaasFormDataEntity(newPaasFormDataEntity);
            activeRuleDTO.setExplainList(beforeSaveVO.getExplainList());
            activeRule(activeRuleDTO);
        }
    }

    @Async(value = "activeRuleThreadPool")
    public void activeRule(ActiveRuleDTO activeRuleDTO) throws XbbException {
        executeRule(activeRuleDTO);
    }

    public void activeRuleBatch(ActiveRuleDTO activeRuleDTO)throws XbbException {
        executeRule(activeRuleDTO);
    }

    public void executeRule(ActiveRuleDTO activeRuleDTO) throws XbbException{
        PaasFormDataEntity paasFormDataEntity = activeRuleDTO.getPaasFormDataEntity();
        PaasFormDataEntity oldPaasFormDataEntity = activeRuleDTO.getOldPaasFormDataEntity();
        Long formId = paasFormDataEntity.getFormId();
        Long dataId = paasFormDataEntity.getId();
        String corpid = activeRuleDTO.getCorpid();
        Long businessRuleId = 0L;
        Integer businessRuleType = ACTIVE_BUSINESS_RULE_TYPE;
        Integer reason = BusinessRuleExecuteEnum.PRODUCER_ERROR.getCode();
        Integer operationType = 0;
        RuleTargetPojo target = new RuleTargetPojo();
        try {
            if (businessRuleUserPermissionHelp.validateUsePermission(corpid)) {
                // 不是旗舰版，并且白名单不为空且不在白名单内
                return;
            }

            Integer excess = 0;
            List<BusinessRulesPoJo> businessRules = activeRuleDTO.getRuleList();
            if (CollectionsUtil.isEmpty(businessRules)) {
                FormBusinessRuleVO businessRuleVO = businessRuleInfoService.get(corpid, formId, activeRuleDTO.getBusinessType(), activeRuleDTO.getSaasMark(), 0);
                businessRules = businessRuleVO.getBusinessRule();
                excess = businessRuleVO.getExcess();
                if (businessRuleVO.getFormulaLimit()) {
                    return;
                }
            }
            if (CollectionsUtil.isEmpty(businessRules)) {
                return;
            }
            if (Objects.isNull(excess) || excess > 0) {
                return;
            }
            if(CollectionsUtil.isNotEmpty(businessRules)){
                Set<Long> formIdList = new HashSet<>();
                Set<Long> workOrderFormIdList = new HashSet<>();
                // 获取表单id
                getFormId(businessRules, workOrderFormIdList, formIdList);
                Map<String, FieldAttrEntity> explainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                if (CollectionsUtil.isNotEmpty(activeRuleDTO.getExplainList())) {
                    explainMap = ExplainUtil.getExplainMapByList(activeRuleDTO.getExplainList());
                } else {
                    // 工作流传过来的，没有字段解释，需要在这边查下
                    PaasFormExplainEntity paasFormExplainEntity = proFormHelp.getExplainEntity(corpid, formId, activeRuleDTO.getBusinessType());
                    explainMap = ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), null);
                }
                ProFormHelp.setDataIdAttr(explainMap);
                // 获取表单id
                Map<Long, PaasFormExplainEntity> formExplainMap = proFormHelp.getFormExplainMap(formIdList, corpid);
                Map<Long, WorkOrderExplainEntity> workOrderExplainMap = proFormHelp.getWorkOrderFormExplainMap(workOrderFormIdList, corpid);
                List<OperationDTO> operationDtoList = new ArrayList<>();
                for (BusinessRulesPoJo businessRulesPoJo : businessRules) {
                    ActiveRulePoJo activeRulePoJo = businessRulesPoJo.getActiveRule();
                    businessRuleId = businessRulesPoJo.getBusinessRuleId();
                    if (Objects.equals(1, activeRuleDTO.getEditFlag())) {
                        // 如果有编辑的话，先执行作废规则
                        businessRuleType = INACTIVE_BUSINESS_RULE_TYPE;

                        ActiveRulePoJo inactiveRule = businessRulesPoJo.getInactiveRule();
                        InactiveRuleDTO inactiveRuleDTO = new InactiveRuleDTO(businessRules, oldPaasFormDataEntity, activeRuleDTO.getExplainList(),
                                activeRuleDTO.getDataId(), activeRuleDTO.getBusinessType(), activeRuleDTO.getSaasMark(), corpid, activeRuleDTO.getLoginUser(),
                                activeRuleDTO.getPlatform(), activeRuleDTO.getHttpHeader(), activeRuleDTO.getBrowserInfo(), activeRuleDTO.getIp(), activeRuleDTO.getLocale(), activeRuleDTO.getIsImport());
                        inactiveRuleDTO.setBusinessRuleInfoId(businessRuleId);
                        boolean flag = formDataInactiveRuleHelp.executeRule(inactiveRuleDTO, inactiveRule, formExplainMap, workOrderExplainMap, explainMap, oldPaasFormDataEntity, operationDtoList);
                        if (!flag) {
                            RuleTargetPojo ruleTargetPojo = inactiveRule.getRule().getTarget();
                            // 记录日志
                            BusinessRuleLogSaveDTO businessRuleLogSaveDTO = new BusinessRuleLogSaveDTO(activeRuleDTO.getSaasMark(), activeRuleDTO.getBusinessType(), formId, activeRuleDTO.getDataId(),
                                    corpid, activeRuleDTO.getLoginUser(), activeRuleDTO.getPlatform(), activeRuleDTO.getHttpHeader(), activeRuleDTO.getBrowserInfo(),
                                    INACTIVE_BUSINESS_RULE_TYPE, ruleTargetPojo, activeRuleDTO.getIp(), activeRuleDTO.getLocale());
                            setLogger(businessRuleLogSaveDTO, businessRuleId, inactiveRule.getRule().getOperationType(), BusinessRuleExecuteEnum.PRECONDITION_CHECK_FAILED.getMessage(), BusinessRuleExecuteEnum.PRECONDITION_CHECK_FAILED.getCode(),
                                    ruleTargetPojo, inactiveRule.getRule().getOperationType(), 0, 1);
                        }
                    }
                    if (Objects.isNull(activeRulePoJo)) {
                        continue;
                    }
                    if (Objects.equals(activeRulePoJo.getEnable(), 0)) {
                        continue;
                    }
                    // 生效时规则
                    RulePoJo rulePoJo = activeRulePoJo.getRule();
                    if (Objects.nonNull(rulePoJo)) {
                        // 校验下前置条件
                        target = rulePoJo.getTarget();
                        operationType = rulePoJo.getOperationType();
                        businessRuleType = ACTIVE_BUSINESS_RULE_TYPE;
                        BusinessRuleInfoPojo businessRuleInfoPojo = new BusinessRuleInfoPojo();
                        businessRuleInfoPojo.setThisExplainMap(explainMap);
                        businessRuleInfoPojo.setFormExplainMap(formExplainMap);
                        businessRuleInfoPojo.setWorkOrderExplainMap(workOrderExplainMap);
                        businessRuleInfoPojo.setBusinessType(activeRuleDTO.getBusinessType());
                        businessRuleInfoPojo.setSaasMark(activeRuleDTO.getSaasMark());
                        businessRuleInfoPojo.setCorpid(corpid);
                        businessRuleInfoPojo.setOperationType(rulePoJo.getOperationType());
                        // 为前置过滤条件赋值
                        businessRuleInfoPojo.setFormId(paasFormDataEntity.getFormId());
                        boolean flag = businessRuleConditionHelp.validatePreCondition(rulePoJo.getPreConditions(), paasFormDataEntity, businessRuleInfoPojo);
                        if (!flag) {
                            // 记录日志

                            BusinessRuleLogSaveDTO businessRuleLogSaveDTO = new BusinessRuleLogSaveDTO(activeRuleDTO.getSaasMark(), activeRuleDTO.getBusinessType(), formId, activeRuleDTO.getDataId(),
                                    corpid, activeRuleDTO.getLoginUser(), activeRuleDTO.getPlatform(), activeRuleDTO.getHttpHeader(), activeRuleDTO.getBrowserInfo(),
                                    ACTIVE_BUSINESS_RULE_TYPE, target, activeRuleDTO.getIp(), activeRuleDTO.getLocale());
                            setLogger(businessRuleLogSaveDTO, businessRuleId, rulePoJo.getOperationType(), BusinessRuleExecuteEnum.PRECONDITION_CHECK_FAILED.getMessage(), BusinessRuleExecuteEnum.PRECONDITION_CHECK_FAILED.getCode(),
                                    target, rulePoJo.getOperationType(), 0, 1);
                            continue;
                        }
                        OperationDTO operationDTO = new OperationDTO();
                        BeanUtil.copyProperties(activeRuleDTO, operationDTO);

                        businessRuleInfoPojo.setRuleTargetPojo(target);
                        operationDTO.setType(activeRulePoJo.getType());
                        operationDTO.setOperationType(rulePoJo.getOperationType());
                        operationDTO.setTarget(target);
                        operationDTO.setFormId(activeRuleDTO.getPaasFormDataEntity().getFormId());
                        // 过滤掉为空的数据
                        List<OperationsPojo> operationList = rulePoJo.getOperations();
                        operationDTO.setOperations(operationList);
                        operationDTO.setBusinessRuleInfoId(businessRulesPoJo.getBusinessRuleId());
                        operationDTO.setBusinessRuleType(1);
                        Map<String, FieldAttrEntity> targetExplainMap = getTargetExplainMap(businessRuleInfoPojo);
                        if (Objects.equals(RuleOperationEnum.ONLY_INSERT.getType(), rulePoJo.getOperationType()) && Objects.equals(SaasMarkEnum.PAAS.getCode(), target.getLinkSaasMark())) {
                            operationDTO.setPaasFormDataEntity(paasFormDataEntity);
                            operationDTO.setTargetExplain(null);
                            operationDTO.setThisExplain(null);
                            operationDtoList.add(operationDTO);
                        } else {
                            List<FilterConditionsPoJo> filterConditions = rulePoJo.getFilterConditions();

                            businessRuleInfoPojo.setTargetExplainMap(targetExplainMap);
                            // 获取关联数据的集合
                            getFormDataMap(paasFormDataEntity, activeRuleDTO.getExplainList(), businessRuleInfoPojo);
                            // 过滤条件整合
                            BusinessRuleConditionPojo businessRuleConditionPojo = businessRuleConditionHelp.getConditionList(filterConditions, paasFormDataEntity, businessRuleInfoPojo);

                            List<ConditionsEntityExt> conditionList = businessRuleConditionPojo.getConditionList();
                            if (Objects.equals(target.getLinkBusinessType(), XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode())) {
                                conditionList.add(new ConditionsEntityExt(FieldTypeEnum.LOG_TYPE.getAlias(),"",FieldTypeEnum.LOG_TYPE.getType(), ConditionEnum.EQUAL.getSymbol(), Collections.singletonList(0)));
                            }
                            List<ConditionsEntityExt> subConditionList = businessRuleConditionPojo.getSubConditionList();
                            // 没有条件不执行更新，但是不影响插入
                            if (CollectionsUtil.isEmpty(conditionList) && CollectionsUtil.isEmpty(subConditionList)) {
                                LOG.error("not have condition");
                                continue;
                            }
                            List<List<ConditionsEntityExt>> shouldConditionList = new ArrayList<>();
                            // 更新
                            operationDTO.setFilterConditionList(filterConditions);
                            operationDTO.setPaasFormDataEntity(paasFormDataEntity);
                            operationDTO.setShouldConditionList(shouldConditionList);
                            operationDTO.setConditionList(conditionList);
                            operationDTO.setSubConditionList(subConditionList);
                            operationDTO.setAttr(businessRuleConditionPojo.getAttr());
                            operationDTO.setTargetExplain(null);
                            operationDTO.setThisExplain(null);
                            operationDTO.setFormDataMap(businessRuleInfoPojo.getFormDataMap());
                            operationDtoList.add(operationDTO);
                        }
                    }
                }
                if (CollectionsUtil.isNotEmpty(operationDtoList)) {
                    OperatorBatchDTO operatorBatchDTO = new OperatorBatchDTO(operationDtoList, activeRuleDTO.getSaasMark(), activeRuleDTO.getBusinessType(), formId, dataId, corpid, activeRuleDTO.getLoginUser(), activeRuleDTO.getPlatform(),
                            activeRuleDTO.getHttpHeader(), activeRuleDTO.getBrowserInfo(), activeRuleDTO.getIp(), activeRuleDTO.getLocale(), activeRuleDTO.getIsImport());
                    sendMessage(operatorBatchDTO);
                }
            }
        } catch (XbbException e) {
            // 记录日志
            if (Objects.equals(ACTIVE_BUSINESS_RULE_TYPE, businessRuleType)) {
                BusinessRuleLogSaveDTO businessRuleLogSaveDTO = new BusinessRuleLogSaveDTO(activeRuleDTO.getSaasMark(), activeRuleDTO.getBusinessType(), formId, activeRuleDTO.getDataId(),
                        businessRuleType, corpid, activeRuleDTO.getLoginUser(), activeRuleDTO.getPlatform(), activeRuleDTO.getHttpHeader(), activeRuleDTO.getBrowserInfo(), activeRuleDTO.getIp(), activeRuleDTO.getLocale());
                setLogger(businessRuleLogSaveDTO, businessRuleId, operationType, e.getMsg(), reason, target, 0, 0, 0);
            }
        } catch (Exception e) {
            LOG.error("formDataActiveRuleHelp.validateDataByActiveRule生效规则校验失败：", e);
        }
    }
    /**
     * 发送消息，执行规则
     * @param operatorBatchDTO
     * @throws XbbException
     */
    @Override
    public void sendMessage(OperatorBatchDTO operatorBatchDTO) throws XbbException {
        // saas 不允许插入数据
        businessRuleProducer.sendMessage(operatorBatchDTO);

    }

}
